﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Windows.Forms;

namespace DbView
{
	interface IFieldSelecterView
	{
		// display the fields from the list given
		void DisplaySelectedFields(List<String> fieldNames, bool isPartialList);
		void DisplaySelectedTableName(String tableName);
	}

	class FieldSelectorPresenter
	{
		// fields copied in 72-char/line blocks or a list of 1 field/line
		public enum CopyMode { block, list };

		public FieldSelectorPresenter()
		{
			this.fieldNames = new List<string>();
			this.selectedNames = new List<string>();
		}

		public void AttachView(IFieldSelecterView view) { this.view = view; }
		// This presenter will now share a model with the current presenter
		public void AttachModel(Model model) { this.model = model; }

		///////////////////////////////////////////////////////////////////////
		// Api for view to use
		public void UserOpenedFieldSelecter(String tableName)
		{
			if (tableName.Length > 0)
				this.TableSelected(tableName);
		}

		public void TableSelected(String tableName)
		{
			this.tableName = tableName;
			// textTable.Text = this.m_Table;
			this.matchString = "";
			this.FieldPickerPopulate();
			this.view.DisplaySelectedTableName(this.tableName);
		}

		public void ShowAll()
		{
			this.SetMatchString("");
		}

		public void UpdateSelection(List<String> selected)
		{
			this.CopySelection(selected, CopyMode.block);
		}

		public void CopyFields(CopyMode copyMode)
		{
			this.CopySelection(this.selectedNames, copyMode);
		}

		// new: combine the best
		public void CopySelection(List<String> selected, CopyMode copyMode)
		{
			int maxWidth = (copyMode == CopyMode.block) ? 72 : 0;     // width break 
			if (selected.Count > 0)
				// refactor to form?
				System.Windows.Forms.Clipboard.SetText(this.BuildClipString(selected, maxWidth, this.GetPrefix()));
		}


		public bool KeyPress(char c)
		{
			if ((c >= '0' && c <= '9')
				|| (c >= 'A' && c <= 'Z')
				|| (c >= 'a' && c <= 'z'))
			{
				this.SetMatchString(this.matchString + c);
				return true;
			}
			else if (c == 8)
			{
				int l = this.matchString.Length;
				if (l > 0)
				{
					this.SetMatchString(this.matchString.Substring(0, l - 1));
					return true;
				}
			}
			else if (c == 27) // escape 
			{
				this.SetMatchString("");
			}
			return false;
		}

		public void SetPrefix(bool isChecked) { this.prefixSet = isChecked; this.SetMatchString(this.matchString); }

		public string Prefix
		{
			get
			{
				if (!this.prefixSet) return ""; // prefix not checked
				// if it is checked use table name if no alias is entered
				return (this.prefix.Length > 0) ? this.prefix : this.tableName;
			}
		}

		public void SetPrefixString(String prefixString) { this.prefix = prefixString; this.SetMatchString(this.matchString); }

		///////////////////////////////////////////////////////////////////////
		// Implementation from here
		private void FieldPickerPopulate()
		{
			// find fields
			this.GetSchemaInfo();
			// populate the view with them all
			this.SetMatchString(""); // ie select all names
			// this.m_View.DisplaySelectedFields(this.m_FieldNames, false);
		}

		private void GetSchemaInfo()
		{
			DataTable data;
			this.model.DataSource.GetTableSchema(this.tableName, out data, false);
			this.fieldNames.Clear();
			foreach (DataRow dr in data.Rows)
				this.fieldNames.Add(dr[0].ToString());
		}


		private void SetMatchString(String NewMatch)
		{
			//if (NewMatch.CompareTo(this.m_MatchString) == 0)
			//	return; // do nothing if nothing to do.
			this.matchString = NewMatch;
			// create a matching subset 
			this.selectedNames.Clear();

			bool filterActive = false; // flags at least one field removed.
			foreach (String fieldname in this.fieldNames)
			{
				if (this.Matches(fieldname, this.matchString))
					this.selectedNames.Add(fieldname);
				else
					filterActive = true;
			}
			this.view.DisplaySelectedFields(this.selectedNames, filterActive);
		}

		private bool Matches(String target, string pattern)
		{
			if (pattern.Length == 0) // no search set
				return true;
			// simple contains
			if (target.ToUpper().IndexOf(pattern.ToUpper()) >= 0)
				return true;
			return false;
		}

		private string BuildClipString(List<String> selectedFields, int maxWidth, string tableAlias)
		{
			int runningCount = -2; // hack as 1st +2 unnecessary
			string outString = "";
			foreach (String s1 in selectedFields)
			{
				// Oh dear. Calling code is tangled so names may be either prefixed already or not.
				// hence only add prefix if there is a table alias and it is not already prefixed
				string s = (tableAlias.Length > 0 && s1.IndexOf(".") == -1) ? tableAlias + "." + s1 : s1;

				runningCount += 2;
				if (outString.Length > 0)
					outString += ", ";

				if (runningCount + s.Length > maxWidth)
				{
					outString += "\n";
					runningCount = 0;
				}
				outString += s;
				runningCount += s.Length;
			}
			return outString;
		}

		private string GetPrefix()
		{
			string prefix = "";
			if (this.prefixSet)
			{
				prefix = (this.prefix.Length > 0) ? this.prefix
												: this.tableName;
			}
			return prefix;
		}

		Model model; // for schema access
		IFieldSelecterView view; // for UI

		string tableName;			// the table name 
		List<String> fieldNames; // always all available fields
		string matchString;   // the (hidden chars typed by the user
		List<String> selectedNames; // cut-down list
		// prefix option for scripint fields
		bool prefixSet = false;
		string prefix = "";  // choice of prefix
	}
}
